using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using WebServiceTool.Models;

namespace WebServiceTool.Utilities
{
    /// <summary>
    /// wsdl解析帮助类，提供通用的XML节点查找和解析功能
    /// </summary>
    public class WsdlParsingHelper
    {

        private readonly XmlNamespaceManager _nsmgr;


        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        public WsdlParsingHelper()
        {
            _nsmgr = new XmlNamespaceManager(new NameTable());
            _nsmgr.AddNamespace("wsdl", "http://schemas.xmlsoap.org/wsdl/");
            _nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/wsdl/soap/");
            _nsmgr.AddNamespace("s", "http://www.w3.org/2001/XMLSchema");
        }

        #endregion


        #region 公共方法

        /// <summary>
        ///   解析wsdl文档并获取所有方法信息
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <param name="methods">方法列表</param>
        public void GetMethods(XmlDocument document, List<WebServiceOperation> methods)
        {
            // 查找操作节点
            var operationNodes = FindOperationNodes(document);

            if (operationNodes is null) throw new InvalidOperationException("在WSDL服务中未找到任何方法");

            var methodNames = new HashSet<string>();

            // 遍历所有操作节点并构建方法信息
            foreach (XmlNode operationNode in operationNodes)
            {
                var method = CreateWebServiceMethod(document, operationNode, methodNames);
                if (method is null) continue;

                // var namespaceManager = CreateNamespaceManager(document);
                // 获取并解析输入参数
                if (TryAddInputParameters(method, operationNode, _nsmgr))
                {
                    methods.Add(method);
                }
            }
        }

        /// <summary>
        /// 解析SOAP响应
        /// </summary>
        /// <param name="responseContent">响应内容</param>
        /// <returns>解析后的结果</returns>
        public string ParseSoapResponse(string responseContent)
        {
            // 简单实现：提取Body内容
            var startIndex = responseContent.IndexOf("<soap:Body>", StringComparison.Ordinal);
            var endIndex = responseContent.IndexOf("</soap:Body>", StringComparison.Ordinal);
            if (startIndex > 0 && endIndex > 0)
            {
                return responseContent.Substring(startIndex + 11, endIndex - startIndex - 11);
            }
            return responseContent;
        }

        /// <summary>
        /// 构建SOAP请求信封
        /// </summary>
        /// <param name="document"> </param>
        /// <param name="targetNamespace">服务命名空间</param>
        /// <param name="methodName">方法名</param>
        /// <param name="parameters">参数列表</param>
        /// <returns>SOAP请求信封XML</returns>
        public string BuildSoapEnvelope(XmlDocument document, string targetNamespace, string methodName,
            List<InputParameter> parameters)
        {
            var envelope = new StringBuilder();
            envelope.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            envelope.AppendLine("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
                                $"xmlns:{GetNamespacePrefix(targetNamespace)}=\"{targetNamespace}\">");
            envelope.AppendLine("  <soap:Header/>");
            envelope.AppendLine("  <soap:Body>");

            // 添加方法调用
            envelope.AppendLine($"    <{methodName} xmlns=\"{targetNamespace}\">");

            // 添加参数
            foreach (var parameter in parameters)
            {
                if (!string.IsNullOrEmpty(parameter.Name))
                {
                    var value = parameter.Value?.ToString() ?? "";
                    value = value.Replace("<", "&lt;").Replace(">", "&gt;");
                    envelope.AppendLine($"      <{parameter.Name}>{value}</{parameter.Name}>");
                }
            }

            envelope.AppendLine($"    </{methodName}>");
            envelope.AppendLine("  </soap:Body>");
            envelope.AppendLine("</soap:Envelope>");

            return envelope.ToString();
        }

        /// <summary>
        /// 获取目标命名空间
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <returns>目标命名空间</returns>
        public string GetTargetNamespace(XmlDocument document)
        {
            // var namespaceManager = CreateNamespaceManager(document);
            var targetNamespaceNode = document.SelectSingleNode("//wsdl:definitions/@targetNamespace", _nsmgr);
            return targetNamespaceNode?.Value ?? string.Empty;
        }

        /// <summary>
        /// 获取端点URL
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <returns>端点URL</returns>
        public string GetEndpointUrl(XmlDocument document)
        {
            
            var endpointNode = document.SelectSingleNode("//soap:address/@location", _nsmgr);
            return endpointNode?.Value ?? string.Empty;
        }

        /// <summary>
        /// 获取方法URL
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <param name="methodName">方法名称</param>
        /// <returns>方法URL</returns>
        public string GetMethodUrl(XmlDocument document, string methodName)
        {
            var targetNamespace = GetTargetNamespace(document);
            return $"{targetNamespace}{methodName}";
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 查找操作节点
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <returns>操作节点列表</returns>
        private XmlNodeList FindOperationNodes(XmlDocument document)
        {
            // var namespaceManager = CreateNamespaceManager(document);
            return document.SelectNodes("//wsdl:operation", _nsmgr);
        }


        /// <summary>
        /// 创建WebService方法
        /// </summary>
        /// <param name="document">WSDL文档</param>
        /// <param name="operationNode">操作节点</param>
        /// <param name="methodNames">方法名称集合</param>
        /// <returns>WebService方法</returns>
        private WebServiceOperation CreateWebServiceMethod(XmlDocument document, XmlNode operationNode, HashSet<string> methodNames)
        {
            var nameAttr = operationNode.Attributes?["name"]?.Value;
            var description = operationNode.SelectSingleNode(".//wsdl:documentation", _nsmgr)?.InnerText;

            // 如果方法名不存在或者已经存在，则跳过
            if (nameAttr is null || !methodNames.Add(nameAttr))
                return null;

            return new WebServiceOperation
            {
                Name = nameAttr,
                Description = description,
                InputParameters = new List<InputParameter>()
            };
        }

        /// <summary>
        /// 尝试添加输入参数
        /// </summary>
        /// <param name="operation">WebService方法</param>
        /// <param name="operationNode">操作节点</param>
        /// <param name="namespaceManager">命名空间管理器</param>
        /// <returns>是否成功添加输入参数</returns>
        private bool TryAddInputParameters(WebServiceOperation operation, XmlNode operationNode, XmlNamespaceManager namespaceManager)
        {
            // 添加参数验证
            if (operationNode == null) throw new ArgumentNullException(nameof(operationNode));
            if (namespaceManager == null) throw new ArgumentNullException(nameof(namespaceManager));

            // 获取输入节点
            var inputNode = operationNode.SelectSingleNode(".//wsdl:input", namespaceManager);
            if (inputNode is null) return false;

            // 获取消息属性值
            var messageAttrValue = inputNode.Attributes?["message"]?.Value;
            if (string.IsNullOrEmpty(messageAttrValue)) return false;

            // 解析消息节点
            var messageName = RemoveNamespacePrefix(messageAttrValue);
            var document = operationNode.OwnerDocument;
            if (document == null) return false;

            var messageNode = document.SelectSingleNode($"//wsdl:message[@name='{messageName}']", namespaceManager);
            if (messageNode is null) return false;

            // 获取part节点
            var partNode = messageNode.SelectSingleNode(".//wsdl:part", namespaceManager);
            if (partNode is null) return false;

            // 解析元素类型
            var partElement = GetAttributeValue(partNode, "element");
            if (string.IsNullOrEmpty(partElement)) return false;

            var typeName = RemoveNamespacePrefix(partElement);
            var typeNode = document.SelectSingleNode($"//s:element[@name='{typeName}']", namespaceManager);
            if (typeNode is null) return false;

            // 解析元素节点并添加参数
            var elementNodes = typeNode.SelectNodes(".//s:element", namespaceManager);
            if (elementNodes is null) return false;

            foreach (XmlNode elementNode in elementNodes)
            {
                if (TryCreateParameter(elementNode, out var parameter))
                {
                    operation.InputParameters.Add(parameter);
                }
            }

            return true;
        }

        // 尝试创建方法参数
        private bool TryCreateParameter(XmlNode elementNode, out InputParameter parameter)
        {
            parameter = new InputParameter();

            var parameterName = GetAttributeValue(elementNode, "name");
            var parameterTypeAttr = GetAttributeValue(elementNode, "type");

            // 如果字段名或者字段类型为空，则返回失败
            if (string.IsNullOrEmpty(parameterName) || string.IsNullOrEmpty(parameterTypeAttr))
                return false;

            // 解析参数约束（使用null合并运算符简化）
            _ = int.TryParse(GetAttributeValue(elementNode, "minOccurs"), out int minOccurs);
            _ = int.TryParse(GetAttributeValue(elementNode, "maxOccurs"), out int maxOccurs);

            parameter.Name = parameterName;
            parameter.Type = RemoveNamespacePrefix(parameterTypeAttr);
            parameter.MinOccurs = minOccurs;
            parameter.MaxOccurs = maxOccurs;

            return true;
        }

        /// <summary>
        /// 获取命名空间前缀
        /// </summary>
        /// <param name="targetNamespace">目标命名空间</param>
        /// <returns>命名空间前缀</returns>
        private string GetNamespacePrefix(string targetNamespace)
        {
            // 简单实现，实际项目中可能需要更复杂的逻辑
            return "tns";
        }

        #endregion


        #region 私有方法 - XML工具

        // 辅助方法：获取属性值
        private static string GetAttributeValue(XmlNode node, string attributeName)
        {
            return node.Attributes?[attributeName]?.Value;
        }

        // 辅助方法：移除命名空间前缀
        private static string RemoveNamespacePrefix(string value)
        {
            var colonIndex = value.IndexOf(':');
            return colonIndex > 0 ? value.Substring(colonIndex + 1) : value;
        }

        #endregion

    }
}